package com.duckclouddrive.controller;


import com.duckclouddrive.component.RedisComponent;
import com.duckclouddrive.entity.config.AppConfig;
import com.duckclouddrive.entity.constants.Constants;
import com.duckclouddrive.entity.dto.DownloadFileDto;
import com.duckclouddrive.entity.dto.SessionWebUserDto;
import com.duckclouddrive.entity.enums.FileCategoryEnums;
import com.duckclouddrive.entity.enums.FileFolderTypeEnums;
import com.duckclouddrive.entity.enums.ResponseCodeEnum;
import com.duckclouddrive.entity.po.FileInfo;
import com.duckclouddrive.entity.query.FileInfoQuery;
import com.duckclouddrive.entity.vo.FolderVO;
import com.duckclouddrive.entity.vo.ResponseVO;
import com.duckclouddrive.exception.BusinessException;
import com.duckclouddrive.service.FileInfoService;
import com.duckclouddrive.utils.CopyTools;
import com.duckclouddrive.utils.StringTools;
import org.apache.commons.lang3.StringUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.File;
import java.net.URLEncoder;
import java.util.List;

public class CommonFileController extends ABaseController {

    @Resource
    protected FileInfoService fileInfoService;

    @Resource
    protected AppConfig appConfig;

    @Resource
    private RedisComponent redisComponent;

    /**
     * 获取文件夹信息
     * 根据用户ID和文件夹路径，查询并返回文件夹的相关信息
     *
     * @param path 文件夹路径，用于识别需要查询的文件夹
     * @param userId 用户ID，用于识别进行查询的用户
     * @return 返回一个ResponseVO对象，包含查询到的文件夹信息
     */
    public ResponseVO getFolderInfo(String path, String userId) {
        // 将文件夹路径分割成数组，以便后续查询使用
        String[] pathArray = path.split("/");
        // 创建一个文件信息查询对象，用于设置查询条件
        FileInfoQuery infoQuery = new FileInfoQuery();
        // 设置查询的用户ID
        infoQuery.setUserId(userId);
        // 设置查询的文件类型为文件夹
        infoQuery.setFolderType(FileFolderTypeEnums.FOLDER.getType());
        // 设置查询的文件ID数组，即文件夹路径数组
        infoQuery.setFileIdArray(pathArray);
        // 设置查询的排序条件，根据文件ID和路径数组进行排序
        String orderBy = "field(file_id,\"" + StringUtils.join(pathArray, "\",\"") + "\")";
        infoQuery.setOrderBy(orderBy);
        // 根据查询条件，查询文件信息列表
        List<FileInfo> fileInfoList = fileInfoService.findListByParam(infoQuery);
        // 将查询到的文件信息列表转换为前端需要的格式，并返回成功响应
        return getSuccessResponseVO(CopyTools.copyList(fileInfoList, FolderVO.class));
    }

    /**
     * 根据指定的文件夹和文件名获取图片，并将其作为HTTP响应返回
     *
     * @param response     HTTP响应对象，用于设置响应头和内容类型
     * @param imageFolder  图片文件所在的文件夹名称
     * @param imageName    图片文件的名称，包括扩展名
     *
     * 此方法首先检查图片文件夹和图片名称是否有效如果无效，则直接返回，
     * 不进行后续的图片读取和响应处理方法通过获取图片扩展名来设置响应的内容类型，
     * 并设置缓存控制头以指定图片的缓存时间最后，它读取图片文件并将其写入HTTP响应中
     */
    public void getImage(HttpServletResponse response, String imageFolder, String imageName) {
        // 检查图片文件夹或图片名称是否无效，如果无效则直接返回
        if (StringTools.isEmpty(imageFolder) || StringUtils.isBlank(imageName)) {
            return;
        }

        // 获取图片的扩展名
        String imageSuffix = StringTools.getFileSuffix(imageName);
        // 拼接图片文件的完整路径
        String filePath = appConfig.getProjectFolder() + Constants.FILE_FOLDER_FILE + imageFolder + "/" + imageName;

        // 移除扩展名中的点号
        imageSuffix = imageSuffix.replace(".", "");
        // 根据图片扩展名设置响应的内容类型
        String contentType = "image/" + imageSuffix;
        response.setContentType(contentType);

        // 设置缓存控制头，以指定图片的缓存时间（30天）
        response.setHeader("Cache-Control", "max-age=2592000");

        // 读取图片文件并将其写入HTTP响应中
        readFile(response, filePath);
    }

    protected void getFile(HttpServletResponse response, String fileId, String userId) {
        String filePath = null;
        if (fileId.endsWith(".ts")) {
            String[] tsAarray = fileId.split("_");
            String realFileId = tsAarray[0];

            FileInfo fileInfo = fileInfoService.getFileInfoByFileIdAndUserId(realFileId, userId);
            if (fileInfo == null) {
                //分享的视频，ts路径记录的是原视频的id,这里通过id直接取出原视频
                FileInfoQuery fileInfoQuery = new FileInfoQuery();
                fileInfoQuery.setFileId(realFileId);
                List<FileInfo> fileInfoList = fileInfoService.findListByParam(fileInfoQuery);
                fileInfo = fileInfoList.get(0);
                if (fileInfo == null) {
                    return;
                }
                //更具当前用户id和路径去查询当前用户是否有该文件，如果没有直接返回
                fileInfoQuery = new FileInfoQuery();
                fileInfoQuery.setFilePath(fileInfo.getFilePath());
                fileInfoQuery.setUserId(userId);
                Integer count = fileInfoService.findCountByParam(fileInfoQuery);
                if (count == 0) {
                    return;
                }
            }
            String fileName = fileInfo.getFilePath();
            fileName = StringTools.getFileNameNoSuffix(fileName) + "/" + fileId;
            filePath = appConfig.getProjectFolder() + Constants.FILE_FOLDER_FILE + fileName;

        } else {
            FileInfo fileInfo = fileInfoService.getFileInfoByFileIdAndUserId(fileId, userId);
            if (fileInfo == null) {
                return;
            }
            //视频文件读取.m3u8文件
            if (FileCategoryEnums.VIDEO.getCategory().equals(fileInfo.getFileCategory())) {
                // 重新设置文件路径
                // 获取文件后缀名
                String fileNameNoSuffix = StringTools.getFileNameNoSuffix(fileInfo.getFilePath());
                // 拼接文件路径：项目根目录 + /file/ + 文件夹名称（日期+userId+file） + 文件名(index.m3u8) (ts索引文件)
                filePath = appConfig.getProjectFolder() + Constants.FILE_FOLDER_FILE + fileNameNoSuffix + "/" + Constants.M3U8_NAME;
            } else {
                filePath = appConfig.getProjectFolder() + Constants.FILE_FOLDER_FILE + fileInfo.getFilePath();
            }
        }
        File file = new File(filePath);
        if (!file.exists()) {
            return;
        }
        readFile(response, filePath);
    }
    protected  ResponseVO createDownloadUrl(String fileId, String userId) {
        FileInfo fileInfo = fileInfoService.getFileInfoByFileIdAndUserId(fileId,userId);
        if(fileInfo == null){
            throw new BusinessException(ResponseCodeEnum.CODE_600);
        }
        if (fileInfo.getFolderType().equals(FileFolderTypeEnums.FOLDER.getType())){
            throw new BusinessException(ResponseCodeEnum.CODE_600);
        }
        String code = StringTools.getRandomString(Constants.LENGTH_50);
        DownloadFileDto dto = new DownloadFileDto();
        dto.setDownloadCode(code);
        dto.setFileId(fileId);
        dto.setFileName(fileInfo.getFileName());
        dto.setFilePath(fileInfo.getFilePath());
        redisComponent.saveDownloadCode(code,dto);
        return getSuccessResponseVO(code);
    }
    protected void download(HttpServletRequest request, HttpServletResponse response, String code) throws Exception {
        // 从Redis中获取下载文件的凭证信息
        DownloadFileDto downloadFileDto = redisComponent.getDownloadCode(code);
        // 如果凭证信息不存在，则终止下载操作
        if (null == downloadFileDto) {
            return;
        }
        // 构建文件完整路径
        String filePath = appConfig.getProjectFolder() + Constants.FILE_FOLDER_FILE + downloadFileDto.getFilePath();
        // 获取文件名
        String fileName = downloadFileDto.getFileName();
        // 设置响应内容类型为下载附件
        response.setContentType("application/x-msdownload; charset=UTF-8");
        // 根据用户代理设置文件名编码，以确保浏览器正确处理文件名
        if (request.getHeader("User-Agent").toLowerCase().indexOf("msie") > 0) {//IE浏览器
            // 对于IE浏览器，使用UTF-8编码并进行URL编码
            fileName = URLEncoder.encode(fileName, "UTF-8");
        } else {
            // 对于非IE浏览器，将文件名从UTF-8转为ISO8859-1编码
            fileName = new String(fileName.getBytes("UTF-8"), "ISO8859-1");
        }
        // 设置响应头，指定文件以附件形式下载并携带编码后的文件名
        response.setHeader("Content-Disposition", "attachment;filename=\"" + fileName + "\"");
        // 执行文件读取和传输操作
        readFile(response, filePath);
    }
}
